/* Copyright 2009 Requirements Management System 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.mags.remas.view.widgets;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.beanutils.PropertyUtils;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.FocusListener;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.part.EditorPart;
import org.mags.object.common.ParserFormatterUtils;
import org.mags.remas.view.commons.IChangeFocusListener;

/**
 * 
 * @author Mario Gaitan
 *
 */
public class FieldsControl {
	private InputMaker inputMaker = new InputMaker();
	private Composite parent;
	private Map<String, Composite> containers = new HashMap<String, Composite>();
	private Map<String, Control> fields = new HashMap<String, Control>();
	private Map<String, Control> labels = new HashMap<String, Control>();
	private Map<String, Control> buttons = new HashMap<String, Control>();
	@SuppressWarnings("rawtypes")
	private Map<String, List> realComboValues = new HashMap<String, List>();
	private Map<String, String> fieldTypes = new HashMap<String, String>();
	private IChangeFocusListener changeFocusListener;
	private EditorPart editorPart;
	public EditorPart getEditorPart() {
		return editorPart;
	}
	public void setEditorPart(EditorPart editorPart) {
		this.editorPart = editorPart;
	}
	public FieldsControl(IChangeFocusListener changeFocusListener) {
		this.changeFocusListener = changeFocusListener;
	}	
	public IChangeFocusListener getChangeFocusListener() {
		return changeFocusListener;
	}
	public void setChangeFocusListener(IChangeFocusListener changeFocusListener) {
		this.changeFocusListener = changeFocusListener;
	}
	public Map<String, Control> getControls() {
		return fields;
	}
	public void focusLost(FocusEvent e) {
		if(changeFocusListener!=null)
			changeFocusListener.changeFocus(e);
	}
	public void focusGained(FocusEvent e) {
		
	}	
	public void keyPressed(KeyEvent e) {
		if (editorPart!=null && e.stateMask == SWT.CTRL && (e.keyCode=='S'||e.keyCode=='s'))
			editorPart.doSave(null);	
	}	
	public Composite getContainer(String container) {
		return containers.get(container);
	}
	public void removeContainer(String container) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		cmpContainer.dispose();
		containers.remove(container);
	}
	public void dispose(String name) {
		Control control;
		control = (Control)fields.get(name);
		if(control!=null) {
			control.dispose();
			fields.remove(name);
		}
		control = (Control)labels.get(name);
		if(control!=null) {
			control.dispose();
			labels.remove(name);
		}
		control = (Control)buttons.get(name);
		if(control!=null) {
			control.dispose();
			buttons.remove(name);
		}
		fieldTypes.remove(name);
		realComboValues.remove(name);
	}
	public Composite addContainer(String name, String title) {
		Composite container = inputMaker.addContainer(parent, title);
		containers.put(name, container);
		return container;
	}
	public Label addReadText(String container, String name, String label, String defaultValue) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		Label lblLabel = inputMaker.addReadText(cmpContainer, label);
		lblLabel.setText(defaultValue);
		fields.put(name, lblLabel);
		labels.put(name, inputMaker.getLastLabelAdded());
		fieldTypes.put(name, "READTEXT");
		lblLabel.pack();
		return lblLabel;
	}
	public Text addText(String container, String name, String label, int textLimit, String defaultValue) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		final Text txtText = inputMaker.addText(cmpContainer, label, textLimit);
		txtText.setText(defaultValue);
		txtText.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent e) {
				Text txtControl = (Text)e.widget;
				txtControl.setSelection(0, txtControl.getText().length());				
				FieldsControl.this.focusGained(e);
			}
			@Override
			public void focusLost(FocusEvent e) {
				FieldsControl.this.focusLost(e);
			}
		});
		txtText.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				FieldsControl.this.keyPressed(e);
			}
			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
		fields.put(name, txtText);
		labels.put(name, inputMaker.getLastLabelAdded());
		fieldTypes.put(name, "TEXT");
		return txtText;
	}
	public ListValueViewer addListValue(String container, String name, String label) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		final ListValueViewer listValue = inputMaker.addListValue(cmpContainer, label);
		listValue.getControl().addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent e) {
				FieldsControl.this.focusGained(e);
			}
			@Override
			public void focusLost(FocusEvent e) {
				FieldsControl.this.focusLost(e);
			}
		});
		listValue.getControl().addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				FieldsControl.this.keyPressed(e);
			}
			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
		fields.put(name, listValue.getControl());
		labels.put(name, inputMaker.getLastLabelAdded());
		fieldTypes.put(name, "LISTVALUE");
		return listValue;
	}
	public Text addTextArea(String container, String name, String label, int textLimit, String defaultValue) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		final Text txtText = inputMaker.addTextArea(cmpContainer, label, textLimit);
		txtText.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent e) {
				txtText.setSelection(txtText.getText().length(), txtText.getText().length());				
				FieldsControl.this.focusGained(e);
			}
			@Override
			public void focusLost(FocusEvent e) {
				FieldsControl.this.focusLost(e);
			}
		});
		txtText.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				if(e.keyCode==SWT.TAB)
					txtText.traverse(SWT.TRAVERSE_TAB_NEXT);
				FieldsControl.this.keyPressed(e);
				if(e.keyCode==SWT.TAB)	
					e.doit = false;
			}
			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
		txtText.setText(defaultValue);
		fields.put(name, txtText);
		labels.put(name, inputMaker.getLastLabelAdded());
		fieldTypes.put(name, "TEXTAREA");
		return txtText;		
	}
	public Text addTextDate(String container, String name, String label, Date defaultDate) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		Text txtText = inputMaker.addTextDate(cmpContainer, label);
		txtText.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent e) {
				Text txtControl = (Text)e.widget;
				txtControl.setSelection(0, txtControl.getText().length());				
				FieldsControl.this.focusGained(e);
			}
			@Override
			public void focusLost(FocusEvent e) {
				FieldsControl.this.focusLost(e);
			}
		});
		txtText.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				FieldsControl.this.keyPressed(e);
			}
			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
		txtText.setText(ParserFormatterUtils.getInstance().date2Text(defaultDate));
		fields.put(name, txtText);
		labels.put(name, inputMaker.getLastLabelAdded());
		buttons.put(name, inputMaker.getLastButtonAdded());
		fieldTypes.put(name, "TEXTDATE");
		return txtText;
	}
	@SuppressWarnings("rawtypes")
	public Combo addCombo(String container, String name, String label, List list, String propertyText, Object defaultValue) {
		Composite cmpContainer = containers.get(container);
		if(cmpContainer==null)
			throw new RuntimeException("container is not exists");
		Combo cmbCombo = inputMaker.addCombo(cmpContainer, label);
		cmbCombo.addFocusListener(new FocusListener() {
			@Override
			public void focusGained(FocusEvent e) {
				FieldsControl.this.focusGained(e);
			}
			@Override
			public void focusLost(FocusEvent e) {
				FieldsControl.this.focusLost(e);
			}
		});
		cmbCombo.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				FieldsControl.this.keyPressed(e);
			}
			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
		cmbCombo.add("-no selected-");
		if(list!=null) {
			try {
				for(Object i: list) {
					String text = (String)PropertyUtils.getProperty(i, propertyText);
					cmbCombo.add(text);
				}
				cmbCombo.select(list.indexOf(defaultValue)+1);
			} catch(Exception e) {
				throw new RuntimeException(e);
			}
		}
		realComboValues.put(name, list);
		fields.put(name, cmbCombo);
		labels.put(name, inputMaker.getLastLabelAdded());
		fieldTypes.put(name, "COMBO");
		return cmbCombo;
	}
	public void setVisible(String control, boolean visible) {
		if(fields.get(control)!=null)
			fields.get(control).setVisible(visible);
		if(labels.get(control)!=null)
			labels.get(control).setVisible(visible);
		if(buttons.get(control)!=null)
			buttons.get(control).setVisible(visible);
	}
	@SuppressWarnings("rawtypes")
	public List getComboList(String name) {
		return realComboValues.get(name);
	}
	@SuppressWarnings("rawtypes")
	public void setToCombo(String name, Object value) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(control instanceof Combo) {
			Combo combo = (Combo)control;
			List values = realComboValues.get(name);
			int selectedIndex = 0;
			if(value!=null)
				selectedIndex = values.indexOf(value)+1;
			combo.select(selectedIndex);
		} else
			throw new RuntimeException("control is not Combo Type");		
	}
	public Object getFromControl(String name) {
		Control control = fields.get(name);
		if(control instanceof Combo)
			return getFromCombo(name);
		else if(fieldTypes.get(name)!=null && fieldTypes.get(name).equals("TEXTDATE"))
			return getFromTextDate(name);		
		else if(control instanceof Text)
			return getFromText(name);
		else
			return null;
	}
	@SuppressWarnings("rawtypes")
	public Object getFromCombo(String name) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(control instanceof Combo) {
			Combo combo = (Combo)control;
			int selectedIndex = combo.getSelectionIndex();
			if(selectedIndex==0)
				return null;
			else {
				List values = realComboValues.get(name);
				if(values==null)
					throw new RuntimeException("combo value is not exists");
				return values.get(selectedIndex-1);
			}
		} else
			throw new RuntimeException("control is not Combo Type");
	}
	public void setToReadText(String name, String value) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(control instanceof Label) {
			if(value==null)
				((Label)control).setText("");
			else
				((Label)control).setText(value);
		}
		else
			throw new RuntimeException("control is not Text Type");				
	}
	public void setToText(String name, String value) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(control instanceof Text) {
			if(value==null)
				((Text)control).setText("");
			else
				((Text)control).setText(value);			
		}
		else
			throw new RuntimeException("control is not Text Type");		
	}
	public String getFromText(String name) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(control instanceof Text)
			return ((Text)control).getText();
		else
			throw new RuntimeException("control is not Text Type");
	}		
	public void setToTextDate(String name, Date value) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(!fieldTypes.get(name).equals("TEXTDATE"))
			throw new RuntimeException("control is not Text Date Type");
		Text _control = (Text)control;
		if(value==null)
			_control.setText("");
		else
			_control.setText(ParserFormatterUtils.getInstance().date2Text(value));
	}
	public Date getFromTextDate(String name) {
		Control control = fields.get(name);
		if(control==null)
			throw new RuntimeException("control is not exists");
		if(!fieldTypes.get(name).equals("TEXTDATE"))
			throw new RuntimeException("control is not Text Date Type");
		String value = ((Text)control).getText();
		if(value==null||value.equals(""))
			return null;
		else {
			return ParserFormatterUtils.getInstance().parseDate(value);
		}
	}	
	public Composite getParent() {
		return parent;
	}
	public void setParent(Composite parent) {
		this.parent = parent;
	}
	public Display getDisplay() {
		return inputMaker.getDisplay();
	}
	public void setDisplay(Display display) {
		inputMaker.setDisplay(display);
	}
}
